/**
 * Copyright &copy; 2012-2016 <a href="https://github.com/thinkgem/jeesite">JeeSite</a> All rights reserved.
 */
package com.thinkgem.jeesite.modules.front.web.pay.wx;

import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.thinkgem.jeesite.common.utils.wx.MD5;
import com.thinkgem.jeesite.common.utils.wx.RandomStringGenerator;
import com.thinkgem.jeesite.common.utils.wx.WEIXINParams;
import com.thinkgem.jeesite.common.utils.wx.WeixinSign;
import com.thinkgem.jeesite.common.utils.wx.WeixinXmlTool;
import com.thinkgem.jeesite.modules.config.entity.weixin.ConfigWechat;
import com.thinkgem.jeesite.modules.pay.entity.log.EcPayLog;
import com.thinkgem.jeesite.modules.pay.service.log.EcPayLogService;
import com.thinkgem.jeesite.modules.shop.constant.order.ShopOrderConstant;
import com.thinkgem.jeesite.modules.shop.entity.info.ShopOrderInfo;
import com.thinkgem.jeesite.modules.shop.entity.order.ShopOrder;
import com.thinkgem.jeesite.modules.shop.service.order.ShopOrderService;

import net.sf.json.JSONSerializer;

/**
 * 支付Service
 * @author Egan
 * @version 2016-12-15
 */
@Service
@Transactional(readOnly = true)
public class WXPayService {
	private static Log log = LogFactory.getLog(WXPayService.class);
	@Autowired EcPayLogService ecPayLogService;
	@Autowired ShopOrderService shopOrderService;
	
	@Transactional(readOnly = false)
	public Map<String,Boolean> checkPayResult(String orderId,ConfigWechat configWechat) throws Exception{
		Map<String,Boolean> resultMap = new HashMap<String,Boolean>();
		EcPayLog log = new EcPayLog();
        log.setOrgCode(configWechat.getMchId());
        log.setMerChantid(configWechat.getMchId());
        log.setCoNum(orderId);
        // 根据订单号跟商户号  获取支付日志
		EcPayLog ecPayLog = ecPayLogService.getEcPayLogByCoNumOrgCode(log);
		if (ecPayLog != null) {// 有支付日志
        	//1.支付成功 0,支付失败2，结果不确定
        	if ("1".equals(ecPayLog.getPayFlag())) {
        		resultMap.put("canPay", false);
        	} else if ("0".equals(ecPayLog.getPayFlag())) {
        		resultMap.put("canPay", true);
        	} else if ("2".equals(ecPayLog.getPayFlag())) {
        		Boolean flag = verifyPayResult(ecPayLog,configWechat);
        		resultMap.put("canPay", flag);
        	}
        } else {// 没有支付日志，则从来没有支付过
        	resultMap.put("canPay", true);
        }
		return resultMap;
	}
	
	/*
     * (non-Javadoc)
     * 
     * @see
     * com.eb.pay.onlinepay.pay.domain.IPayDomain#verifyPayResult(com.eb.pay.
     * onlinepay.paylog.view.EcPayLogView)
     */
	@Transactional(readOnly = false)
	public boolean verifyPayResult(EcPayLog ecPayLog,ConfigWechat configWechat) {
		boolean flag = false;
    	if (log.isDebugEnabled()) {
            log.debug("at the head of WEIXINPayDomainImpl.verifyPayResult() method");
        }
        String orgCode = ecPayLog.getOrgCode();
        String coNum = ecPayLog.getCoNum();
        // 与银行重新校验
        try {
        	/**
             * 2、记录交互日志，请求校验支付结果开始
             */
            if (log.isDebugEnabled()) {
                log.debug("orgCode=" + orgCode + ";coNum=" + coNum + "的订单请求校验支付结果开始。");
            }
            
            // 3,向微信发起支付
            String randomNo = RandomStringGenerator.getRandomStringByLength(32);
    		String queryStringA = "appid="+configWechat.getAppIdGz()+"&mch_id="+configWechat.getMchId()
            +"&nonce_str="+randomNo+"&out_trade_no="+ecPayLog.getCoNum()+"&key="+configWechat.getAppKey();
    		
            String sign = MD5.MD5Encode(queryStringA).toUpperCase();
            String xmlStr = WeixinXmlTool.getWeixinQueryXml(ecPayLog.getCoNum(),sign,randomNo,configWechat);
            String result = WeixinXmlTool.sendPost(configWechat.getQueryUrl(), xmlStr);
            Map<String,String> map = WeixinXmlTool.getQueryResultFromXml(result);
            if ("SUCCESS".equals(map.get("return_code"))) {//响应成功
            	if("SUCCESS".equals(map.get("result_code"))){//查询成功
            		ecPayLog.setPayFlag("1");
            		flag = false;
            		ShopOrder order = new ShopOrder();
            		ShopOrder shorder = shopOrderService.findByCoNum(map.get("out_trade_no"));
        			order.setCode(map.get("out_trade_no"));
        			SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
        			order.setPayTime(sdf.parse(ecPayLog.getPayTime()));
        			if(shorder.getStatus()==ShopOrderConstant.ORDER_WAIT_PAYMENT){
        			    order.setStatus(ShopOrderConstant.ORDER_PAYMENT_DONE);
        			}
        			shopOrderService.updateOrderForPaySuccess(order);
                }else{
                	ecPayLog.setPayFlag("0");
                	flag = true;
                }
            	//TODO
            }else{//响应失败
            	ecPayLog.setPayFlag("2");
            	flag = false;
            }
        } catch (RuntimeException e) {
        	ecPayLog.setPayFlag("2");
            log.error("出现运行时异常");
        } catch (Exception e) {
        	ecPayLog.setPayFlag("2");
            log.error("e:" + e.getMessage());
        }
        ecPayLogService.updatePayFlag(ecPayLog);
        return flag;
    }
    
	@Transactional(readOnly = false)
    public Map<String,String> forPay(String txnAmt,String coNum,ConfigWechat configWechat,HttpServletRequest req,List<ShopOrderInfo> infos) throws Exception {
    	Map<String, String> paramMap = getSignMap(txnAmt,coNum,configWechat,req,infos);
		// 生成签名
		String sign = WeixinSign.getWeixinPaySign(paramMap);
		paramMap.put("sign", sign);
		// 生成请求xml报文
        String xmlStr = WeixinXmlTool.getWeixinPayXml(paramMap);
        String result = WeixinXmlTool.sendPost(configWechat.getPayUrl(), xmlStr);
        Map<String,String> urlMap = WeixinXmlTool.getPayUrlFromXml(result);
        return urlMap;
    }
	
	@Transactional(readOnly = false)
    public Map<String, String> getSignMap(String txnAmt,String coNum,ConfigWechat configWechat,HttpServletRequest req,List<ShopOrderInfo> infos) {
    	
		Map<String,Object> detailMap = new HashMap<String, Object>();
		detailMap.put("cost_price", txnAmt);
		detailMap.put("receipt_id", coNum);
		List<Map<String,Object>> lst = new ArrayList<Map<String,Object>>();
		for (ShopOrderInfo info: infos) {
			Map<String,Object> goodDetails = new HashMap<String, Object>();
			goodDetails.put("goods_id", info.getProductId());
			goodDetails.put("goods_name", info.getName());
			goodDetails.put("quantity", info.getTotalAmount());
			goodDetails.put("price", info.getPrice());
			lst.add(goodDetails);
		}
		detailMap.put("goods_detail", lst);
		Map<String, String> paramMap = new HashMap<String, String>();	
    	// 金额格式保留两位小数
        int index = txnAmt.indexOf(".");
        if (index < 0) {
        	txnAmt = txnAmt + ".00";
        } else if ((txnAmt.length() - index) < 3) {
            if ((txnAmt.length() - index) == 2) {
            	txnAmt = txnAmt + "0";
            } else if ((txnAmt.length() - index) == 1) {
            	txnAmt = txnAmt + "00";
            }
        } else if ((txnAmt.length() - index) > 3) {// 保留小数超过两位则去除多余的
        	txnAmt = txnAmt.substring(0, index + 3);
        }
		BigDecimal orderAmt = new BigDecimal(txnAmt).multiply(new BigDecimal("100")).setScale(0);
		paramMap.put("appid", configWechat.getAppIdGz());
		paramMap.put("attach", coNum);
		paramMap.put("body", "订单号：" + coNum);
		paramMap.put("detail", JSONSerializer.toJSON(detailMap).toString());
		paramMap.put("mch_id", configWechat.getMchId());
		paramMap.put("nonce_str", RandomStringGenerator.getRandomStringByLength(32));
		paramMap.put("notify_url", configWechat.getNotifyUrl());
		// 扫码支付请求支付路径---统一下单
		paramMap.put("out_trade_no", coNum);
		//用户端ip
		paramMap.put("spbill_create_ip", WEIXINParams.getRemortIP(req));
		paramMap.put("total_fee", orderAmt.toString());
		paramMap.put("trade_type", configWechat.getTradeType());
		paramMap.put("appKey", configWechat.getAppKey());
		return paramMap;
    }
	
	@Transactional(readOnly = false)
    public Map<String, String> getSignMapGZ(String txnAmt,String coNum,String openId,ConfigWechat configWechat,HttpServletRequest req) {
    	Map<String, String> paramMap = new HashMap<String, String>();	
    	// 金额格式保留两位小数
        int index = txnAmt.indexOf(".");
        if (index < 0) {
        	txnAmt = txnAmt + ".00";
        } else if ((txnAmt.length() - index) < 3) {
            if ((txnAmt.length() - index) == 2) {
            	txnAmt = txnAmt + "0";
            } else if ((txnAmt.length() - index) == 1) {
            	txnAmt = txnAmt + "00";
            }
        } else if ((txnAmt.length() - index) > 3) {// 保留小数超过两位则去除多余的
        	txnAmt = txnAmt.substring(0, index + 3);
        }
		BigDecimal orderAmt = new BigDecimal(txnAmt).multiply(new BigDecimal("100")).setScale(0);
		paramMap.put("appid", configWechat.getAppIdGz());
		paramMap.put("attach", coNum);
		paramMap.put("body", coNum);
		paramMap.put("mch_id", configWechat.getMchId());
		paramMap.put("nonce_str", RandomStringGenerator.getRandomStringByLength(32));
		paramMap.put("notify_url", configWechat.getNotifyUrl());
		paramMap.put("openId", openId);
		// 扫码支付请求支付路径---统一下单
		paramMap.put("out_trade_no", coNum);
		//用户端ip
		paramMap.put("spbill_create_ip", WEIXINParams.getRemortIP(req));
		paramMap.put("total_fee", orderAmt.toString());
		paramMap.put("trade_type", configWechat.getTradeTypeGz());
		paramMap.put("appKey", configWechat.getAppKey());
		return paramMap;
    }
	
	@Transactional(readOnly = false)
    public String forResult(String message,ConfigWechat configWechat) throws Exception {
		String result = "";
		if(!"".equals(message)){
			Map<String,String[]> parametersMap = WeixinXmlTool.getPayResultFromXml(message);
	        String result_code = parametersMap.get("result_code")[0];
	        String total_fee = parametersMap.get("total_fee")[0];
	        String bank_type = parametersMap.get("bank_type")[0];
	        String transaction_id = parametersMap.get("transaction_id")[0];
	        String out_trade_no = parametersMap.get("out_trade_no")[0];
	        String time_end = parametersMap.get("time_end")[0];
	        String mch_id = parametersMap.get("mch_id")[0];
	        String sign = parametersMap.get("sign")[0];
	        String stringA = parametersMap.get("stringA")[0];
	        // 验签
	        String key = configWechat.getAppKey();
	        stringA = stringA+"&key="+key;
	        if(log.isDebugEnabled()){
	            log.debug(stringA);
	        }
	        
	        EcPayLog ecPayLog = new EcPayLog();
	        if(MD5.MD5Encode(stringA).toUpperCase().equals(sign)){//签名正确
	        	log.debug("===========:签名正确");
	        	ecPayLog.setCoNum(out_trade_no);
	        	ecPayLog.setMerChantid(mch_id);
	        	ecPayLog.setOrderNo(transaction_id);
	        	ecPayLog.setAccDate(time_end);
	        	ecPayLog.setOrgCode(mch_id);
	        	ecPayLog.setPayDate(time_end);
	        	ecPayLog.setPayType(bank_type);
	        	ecPayLog.setBankId("weixin");
	        	ecPayLog.setBankName("微信扫码支付");
	        	ecPayLog.setAmount(new BigDecimal(total_fee));
	        	if(log.isDebugEnabled()){
	                log.debug("微信验签成功");
	            }
	        	if("SUCCESS".equals(result_code)){//支付成功
	                ecPayLog.setPayFlag("1");
	                result = "sucess";
	            } else{
	                if(log.isDebugEnabled()){
	                    log.debug("支付失败：");
	                }
	                ecPayLog.setPayFlag("0");
	                result = "failure";
	            }
	        	
	        } else{
	        	ecPayLog.setPayFlag("2");
	            log.error("签名不正确");
	        }
	        ecPayLogService.deletePayFlagByLog(ecPayLog);
	        ecPayLogService.save(ecPayLog);
	        ShopOrder order = new ShopOrder();
	        ShopOrder shorder = shopOrderService.findByCoNum(out_trade_no);
	        order.setCode(out_trade_no);
            SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
            order.setPayTime(sdf.parse(ecPayLog.getPayTime()));
            if(shorder.getStatus()==ShopOrderConstant.ORDER_WAIT_PAYMENT){
                order.setStatus(ShopOrderConstant.ORDER_PAYMENT_DONE);
            }	
			shopOrderService.updateOrderForPaySuccess(order);
	    }else{
	    	result = "failure";
	        if(log.isDebugEnabled()){
	            log.debug("no handle, no info.");
	        }
	    }
		
		return result;
	}
}